class BlackDeathCamera extends Camera;

var Vector  CurrentCamLocation;  //Position in worldspace of the camera
var Vector  CurrentCamTargetLocation; //The Center of the Camera Sphere (The point the camera rotates around)
var Rotator CurrentCamTargetRotation;  //The Camera target's rotation
var Vector  CamAcceleration;
var Vector  CamVelocity;
var Vector	CurrentCamViewDir;   //Unit vector in the direction the camera is looking
var Rotator CurrentCamRotation;  //Rotator Camera Angle
var float   DesiredTurn;    //Delta Mouse X
var float   DesiredLookUp;  //Delta Mouse Y


var vector FixedCameraTranslateScale;

var float CamDistanceOffset;

var bool 	bRunning;
var bool    bCamActor;

var(FollowCam) float  FollowCamDist;
var(FollowCam) float  RunningFollowCamDist;
var(FollowCam) Vector CamLookOffset;
var(FollowCam) float  TurnRateRatio;

function UpdateViewTarget(out TViewTarget OutVT, float dt)
{
	local CameraActor	CamActor;
	local Vector        HitLocation, HitNormal;
	local Actor         HitActor;
	local BlackDeathPawn BDP;
	local bool          bHide;
	local float         damageTilt;


	// Default FOV on viewtarget
	OutVT.POV.FOV = DefaultFOV;

	// Viewing through a camera actor
	CamActor = CameraActor(OutVT.Target);
	if( CamActor != None )
	{
		bCamActor = true;
		// In LD cinematic!
		CamActor.GetCameraView(dt, OutVT.POV);

		// Grab aspect ratio from the CameraActor
		bConstrainAspectRatio	= bConstrainAspectRatio || CamActor.bConstrainAspectRatio;
		OutVT.AspectRatio		= CamActor.AspectRatio;

		// CameraActor wants to override the PostProcess settings
		CamPostProcessSettings = CamActor.CamOverridePostProcess;

		// Set my variables to account for current targeting
		CurrentCamLocation = OutVT.POV.Location;
		CurrentCamRotation = OutVT.POV.Rotation;
	}
	// Give Pawn Viewtarget a chance to dictate the camera position
	else if( Pawn(OutVT.Target) != None && Pawn(OutVT.Target).CalcCamera(dt, OutVT.POV.Location, OutVT.POV.Rotation, OutVT.POV.FOV) )
	{
		`log("NOTICE ME: No idea when this happens!");
		CurrentCamRotation = OutVT.POV.Rotation;
		CurrentCamLocation = OutVT.POV.Location;
	}
	// Finally, we can make our own camera!
	else
	{
		
		bCamActor = false;
		//OutVT.Target.GetActorEyesViewPoint(CurrentCamTargetLocation, CurrentCamTargetRotation);
		switch( CameraStyle )
		{
			case 'FollowCam':
				FollowCamUpdate(OutVT, dt);
				//OutVT.Target.GetActorEyesViewPoint(CurrentCamLocation, CurrentCamRotation);
				//CurrentCamLocation = CurrentCamLocation -(Vector(CurrentCamRotation)*CamDistanceOffset);
				break;
			case 'ThirdPerson':
				UpdateAimCamera(OutVT);
				break;
			case 'FirstPerson':
				OutVT.Target.GetActorEyesViewPoint(CurrentCamLocation, CurrentCamRotation);
				break;
		}
		// *********************************************
		HitActor = Trace(   HitLocation,
							HitNormal,
							CurrentCamLocation,
							CurrentCamTargetLocation,
							false, vect(12,12,12),,TRACEFLAG_Blocking);

		if (HitActor != none)
		{
			CurrentCamLocation = HitLocation;
		}
		
		if(BlackDeathPawn(OutVT.Target) != none)//if we have a pawn, see if we need to make him invisible.
		{
			BDP = BlackDeathPawn(OutVT.Target);
			if(CameraStyle == 'FollowCam' || CameraStyle == 'ThirdPerson')//if we're in third person or follow cam
			{
				bHide = (CurrentCamLocation.Z<BDP.Location.Z+BDP.CylinderComponent.CollisionHeight+80)&&VSize(HitLocation-(BDP.Location+CamLookOffset))<BDP.GetCollisionRadius()*1.8;
				if(bHide != BDP.isHidden)
				{
					BDP.ChangeVisibility(!bHide);
				}
			}
			
			//Consider moving this code elsewhere if damagetilt is not global and can be overwritten
			if(BlackDeathHeroPawn(BDP) != none)//For hero pawns, roll the camera
			{
				DamageTilt = BlackDeathHeroPawn(BDP).CalcDamageTilt();
				if(CurrentCamRotation.roll != DamageTilt)
				{
					CurrentCamRotation.roll = Lerp(CurrentCamRotation.roll,DamageTilt,0.15);
				}
			}
			
		}

		OutVT.POV.Location = CurrentCamLocation;
		OutVT.POV.Rotation = CurrentCamRotation;
	}

	// Lets LDs do shake and whatnot
	ApplyCameraModifiers(dt, OutVT.POV);
}

function FollowCamUpdate(TViewTarget OutVT, float dt)
{
	local Vector ViewDir;
	local float  currYaw;
	local float  currPitch;
	local float  desiredYaw;
	local float  desiredPitch;
	local float  followDistance;
	local float  currentDistance;
	//local Vector Cam;
	local Vector Target;
	//local Vector desiredDir;
	local Vector friction;
	
	if( IsZero(CurrentCamTargetLocation) )
	{
		//First time call, we assume the camera will never be at exactly 0,0,0 except the first time the function gets called
		//There should be an OnChangeTarget or OnChangeCamStyle function
		//But I couldn't figure out when the BlackDeathPawn becomes the OutVT.Target and I think it'd be easier for Matt to
		//setup the OnChangeCamStyle function cause he knows the PlayerController better than me.
		CurrentCamTargetLocation = OutVT.Target.Location + CamLookOffset;
		CurrentCamViewDir = Vector(OutVT.POV.Rotation);
		CamAcceleration *= 0;
		CamVelocity *= 0;
	}
	
	//Cam is the current location of the Camera
	//Cam      = CurrentCamLocation;
	//Target is the location of the actor we're following
	Target   = OutVT.Target.Location + CamLookOffset;
	
	ViewDir = CurrentCamViewDir;
	//desiredDir = Normal(Target - Cam);
	
	CamAcceleration = (Target - CurrentCamTargetLocation) * 1;

	friction = CamVelocity * -1;

	CamAcceleration += friction * Clamp(dt * 100, 0, 1);

	CamVelocity += CamAcceleration;

	CurrentCamTargetLocation += CamVelocity;

	//Todo: If the player isn't moving the camera, lerp the camera angle to the desiredDir
	
	currYaw = Atan2(ViewDir.Y, ViewDir.X);
	currPitch = Acos(ViewDir.Z / VSize(ViewDir));
	
	desiredYaw = currYaw + DesiredTurn / TurnRateRatio * dt * 50;
	desiredPitch = fclamp(currPitch - DesiredLookUp / TurnRateRatio * dt * 50, Pi/4, Pi - Pi/4);
	
	ViewDir.Y = Sin(desiredYaw)*Sin(desiredPitch);
	ViewDir.X = Cos(desiredYaw)*Sin(desiredPitch);
	ViewDir.Z = Cos(desiredPitch);
	
	if( bRunning )
		followDistance = RunningFollowCamDist;
	else
		followDistance = FollowCamDist;

	currentDistance = VSize(CurrentCamLocation - CurrentCamTargetLocation);
	currentDistance = Lerp( currentDistance, followDistance, 0.1 );

	CurrentCamLocation = CurrentCamTargetLocation + ViewDir * -currentDistance;
	CurrentCamViewDir = ViewDir;
	CurrentCamRotation = rotator(ViewDir);
}

simulated function UpdateAimCamera(TViewTarget OutVT)
{
	/** old camera code */
	/*local BlackDeathPawn BDP;
	local vector CamStart, CamDir, X, Y, Z;
	local float CollisionRadius;

	BDP = BlackDeathPawn(OutVT.Target);
	if(BDP != none)
	{
		CollisionRadius = BDP.GetCollisionRadius();

		CamStart = BDP.Location+CamLookOffset;
		CurrentCamTargetLocation = CamStart;
		CurrentCamRotation = BDP.GetViewRotation();

		GetAxes(CurrentCamRotation, X, Y, Z);
		X *= CollisionRadius * FixedCameraTranslateScale.X;
		Y *= CollisionRadius * FixedCameraTranslateScale.Y;
		Z *= CollisionRadius * FixedCameraTranslateScale.Z;
		CamDir = X + Y + Z;
		 
		CurrentCamLocation = CamStart - CamDir;
		CurrentCamViewDir = CamDir;
	}
	else
	{
		CurrentCamRotation = Rotation;
		CurrentCamLocation = Location;
	}*/
	
	/** Temporary quick camera code */
	local vector Loc, InitialLoc;
	local Rotator Rot;

	OutVT.Target.GetActorEyesViewPoint(InitialLoc, Rot);
	CurrentCamTargetLocation = InitialLoc;
	
	Loc = InitialLoc;
	Loc += -Vector(Rot)*CamDistanceOffset;
	CurrentCamLocation = Loc;
	CurrentCamRotation = Rot;
}

simulated function ToggleRunning()
{
	bRunning = !bRunning;
}

simulated function ToggleShoulder()
{
	FixedCameraTranslateScale.Y = -FixedCameraTranslateScale.Y;
}

DefaultProperties
{
	FollowCamDist=65.f
	RunningFollowCamDist=70.f
	DesiredTurn=50.f
	DesiredLookUp = 50.f;
	TurnRateRatio=15000.f
	CamLookOffset=(X=-0,Y=0,Z=25)
	CamDistanceOffset = 60 //temporary var for UpdateAimCamera
	
	FixedCameraTranslateScale=(X=0,Y=0,Z=0)

	DefaultFOV=100.f
	
	bRunning = false;
	bCamActor = false;
}